package com.yanggu.payment.config;


import com.wechat.pay.contrib.apache.httpclient.Credentials;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.util.Objects;

@Data
@Slf4j
@Configuration
@PropertySource("classpath:wxpay.properties") //读取配置文件
@ConfigurationProperties(prefix = "wxpay") //读取wxpay节点
public class WeiXinPayConfig implements InitializingBean {

    // 商户号
    private String mchId;

    // 商户API证书序列号
    private String mchSerialNo;

    // 商户私钥文件
    private String privateKeyPath;

    // APIv3密钥
    private String apiV3Key;

    // APPID
    private String appid;

    // 微信服务器地址
    private String domain;

    // 接收结果通知地址
    private String notifyDomain;

    // APIv2密钥
    private String partnerKey;

    /**
     * 商户的私钥文件
     */
    private PrivateKey merchantPrivateKey;

    /**
     * 商户的私钥文件
     */
    @Override
    public void afterPropertiesSet() {
        try {
            merchantPrivateKey = PemUtil.loadPrivateKey(Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream(privateKeyPath)));
        } catch (Exception e) {
            throw new RuntimeException("私钥文件不存在", e);
        }
    }

    /**
     * 初始化签名生成器
     *
     * @return
     */
    @Bean
    public Credentials wechatPay2Credentials() {
        log.info("初始化微信签名生成器");
        //私钥签名对象
        PrivateKeySigner signer = new PrivateKeySigner(mchSerialNo, merchantPrivateKey);

        //签名生成器
        return new WechatPay2Credentials(mchId, signer);
    }

    /**
     * 获取签名验证器
     *
     * @return
     */
    @Bean
    public Verifier getVerifier(Credentials credentials) throws Exception {

        // 获取证书管理器实例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();
        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(mchId, credentials, apiV3Key.getBytes(StandardCharsets.UTF_8));
        log.info("初始化微信签名校验器");

        // 从证书管理器中获取verifier
        return certificatesManager.getVerifier(mchId);
    }

    /**
     * 初始化微信请求对象
     * 添加了拦截器, 自动处理了请求签名和响应验签
     *
     * @return
     */
    @Bean(name = "wxPayClient")
    public CloseableHttpClient getWxPayClient(Credentials wechatPay2Credentials,
                                              Verifier verifier) {

        log.info("初始化wxPayClient对象");
        return WechatPayHttpClientBuilder.create()
                //添加了签名生成器
                .withCredentials(wechatPay2Credentials)
                //添加了签名校验器
                .withValidator(new WechatPay2Validator(verifier))
                .build();
    }

    /**
     * 初始化微信请求对象 添加了拦截器, 自动处理了请求签名, 但是不处理响应签名, 例如对账接口
     *
     * @param wechatPay2Credentials
     * @return
     */
    @Bean(name = "wxPayClientWithNoValidaResponse")
    public CloseableHttpClient getWxPayClientWithNoValidaResponse(Credentials wechatPay2Credentials) {

        log.info("初始化wxPayClientWithNoValidaResponse对象");
        return WechatPayHttpClientBuilder.create()
                //添加了签名生成器
                .withCredentials(wechatPay2Credentials)
                //为true表示不进行验签
                .withValidator(response -> true)
                .build();
    }

    /**
     * 初始化回调签名校验器
     * 例如支付回调、退款回调均需要手动验签
     * 1. 保证回调接口是微信调用(身份认证)
     * 2. 使用对称密钥解密数据(加密数据)
     *
     * @param verifier
     * @return
     */
    @Bean
    public NotificationHandler weiXinPayNotificationHandler(Verifier verifier) {
        log.info("初始化回调签名校验器");
        return new NotificationHandler(verifier, apiV3Key.getBytes(StandardCharsets.UTF_8));
    }

}
